home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / blix / blixsound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  28.6 KB  |  1,103 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*_______________________________________________________________________
  18.  |
  19.  | blixsound.c - handles all the sound effects for blix.
  20.  |
  21.  | it is partialy a copy of bzsound written by Chris Fouts.
  22.  | There was no need to re-invent it. This is quite a piece of good
  23.  | software. Thanks Chris.
  24.  |
  25.  |
  26.  | Modified to read different data from a different place
  27.  | and to allow for a continous tune to be played
  28.  | also fixed a bug on indigo^2, and added support for
  29.  | volume change in audio control panel.
  30.  | Also removed the complicated explosion sound handling. There are now
  31.  | only three pan position for the sound (-1, 0, 1) (= left, middle, right)
  32.  | which saves quite some memory (left and right share the storage), and
  33.  | only one depth. The sound for the lift also pans.
  34.  |
  35.  |        Frans van Hoesel - Xtreme Graphics Software.
  36.  |        January, 1994
  37.  */
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44. /*________________________________________________________________________
  45.  |
  46.  | BZ - Multiplayer tank game - Sound support.
  47.  |
  48.  |                    Chris Fouts - Silicon Graphics, Inc.
  49.  |                    October, 1991
  50.  |________________________________________________________________________
  51.  |                                                    
  52.  |      Copyright (c) 1990 SGI   All Rights Reserved 
  53.  |      THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SGI  
  54.  |      The copyright notice above does not evidence any   
  55.  |      actual or intended publication of such source code,  
  56.  |      and is an unpublished work by Silicon Graphics, Inc.  
  57.  |      This material contains CONFIDENTIAL INFORMATION that  
  58.  |      is the property of Silicon Graphics, Inc. Any use,
  59.  |      duplication or disclosure not specifically authorized  
  60.  |      by Silicon Graphics is strictly prohibited.  
  61.  |                                                          
  62.  |      RESTRICTED RIGHTS LEGEND:                        
  63.  |      Use, duplication or disclosure by the          
  64.  |      Government is subject to restrictions           
  65.  |      as set forth in subdivision (c)(1)(ii) of    
  66.  |      the Rights in Technical Data and Computer         
  67.  |      Software clause at DFARS 52.227-7013,                 
  68.  |      and/or in similar or successor clauses in the FAR,    
  69.  |      DOD or NASA FAR Supplement. Unpublished- rights        
  70.  |      reserved under the Copyright Laws of the United States. 
  71.  |      Contractor is SILICON GRAPHICS, INC., 2011 N. Shoreline 
  72.  |      Blvd., Mountain View, CA 94039-7311                    
  73. */  
  74.                                                           
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <fcntl.h>
  78. #include <errno.h>
  79. #include <sys/types.h>
  80. #include <sys/prctl.h>
  81. #include <string.h>
  82. #include <signal.h>
  83. #include <malloc.h>
  84. #include <unistd.h>
  85. #include <fcntl.h>
  86. #include <audio.h>
  87. #include <invent.h>
  88. #include <gl/gl.h>
  89.  
  90. #include "aiff.h"
  91. #include "blixsound.h"
  92. #include "blix.h"
  93.  
  94. int pause( void ) ;
  95.  
  96. /* as the timeslice is 0.3 seconds it seems appropiate to make this
  97.  * TIMECHUNK variable at least 0.3 seconds. 0.1 seems to work great though
  98.  * A time of 0.3 seconds makes it possible that the requested sound is
  99.  * delayed by that much.
  100.  */
  101. #define TIMECHUNK 0.1             /* duration of buffer data */
  102. /*
  103.  * we're going to nail down the value of infinity for the IEEE conversion
  104.  * routine below: math.h yields to local definition of HUGE_VAL
  105.  */
  106. union {
  107.     unsigned long n[2];   /* initialized in main */
  108.     double        d;
  109. } _inf_union;
  110. #define HUGE_VAL _inf_union.d;
  111. #include <math.h>
  112.  
  113. typedef union {
  114.     unsigned char b[2];
  115.     short         s;
  116. } align_short_t;
  117.  
  118. typedef union {
  119.     unsigned char b[4];
  120.     long         l;
  121. } align_long_t;
  122.  
  123.  
  124. #define    MAX_AUDIO_PORTS    3
  125.  
  126. static unsigned long orig_left_gain ;
  127. static unsigned long orig_right_gain ;
  128. static unsigned long orig_output_rate ;
  129. static unsigned long curr_left_gain ;
  130. static unsigned long curr_right_gain ;
  131. static long sound_size[SFX_N_SOUNDS] ;
  132. static long sound_repeat[SFX_N_SOUNDS] ;
  133. static short *sound_data[SFX_N_SOUNDS] ;
  134. static char *sound_file[SFX_N_SOUNDS] = {
  135.         "snd/welcome.aiff",
  136.         "snd/beep.aiff",
  137.         "snd/explosion.aiff",
  138.         "snd/explosion.aiff",    /* extra for panned sound */
  139.         "snd/lift.aiff",
  140.         "snd/lift.aiff",    /* same for lift sound */
  141.         "snd/tune_a.aiff",
  142.         "snd/tune_b.aiff",
  143.         "snd/tune_c.aiff",
  144.         "snd/donk_c.aiff",
  145.         "snd/planet.aiff",
  146.         "snd/pop.aiff",        /* yes, for pop-up menu */
  147.         "snd/goodbye.aiff"
  148.         } ;
  149. static short    *new_sound_data ;
  150. static long    new_sound_size ;
  151. static long    new_sound_repeat; 
  152. static int    new_sound = 0 ;
  153. static char    *filename;         /* input file name */
  154. static int    bytes_per_samp;        /* sample width */
  155. static int    samps_per_frame;    /* frame size */
  156. static int    frames_per_sec;        /* sample rate */
  157. static ALport    audio_port[MAX_AUDIO_PORTS+1] ;/* foreground audio ports */
  158. static int    sound_child = 0 ;
  159. static int    sound_enabled = 0 ;
  160. static int    has_sound_hw = 0 ;
  161. static int    tune_enabled = 0;
  162.  
  163. static unsigned long    gain_settings[] =
  164.             { 0, 2, 3, 5, 9, 16, 29, 50, 91, 156, 255 } ;
  165. static int    gain_index ;
  166.  
  167.  
  168. static int check_for_audio_hw( void ) ;
  169. static double ConvertFromIeeeExtended( char *bytes ) ;
  170. static char *init_audio( int fd, audio_params_t *audio_params,
  171.                     ssnd_chunk_t *ssnd_data, comm_chunk_t *comm_data,
  172.                     long *size ) ;
  173. static ALport init_audio_port( int all ) ;
  174. static void init_pan_data(int sound) ;
  175. static char *load_aiff_file( char *dir, char *name, long *size ) ;
  176. static char *read_aiff_file( int fd, long *size ) ;
  177. static int read_chunk_header( int fd, chunk_header_t *chunk_header ) ;
  178. static void read_comm_chunk( int fd, comm_chunk_t *comm_data,
  179.                     audio_params_t *audio_params ) ;
  180. static void read_form_chunk( int fd, chunk_header_t *chunk_header ) ;
  181. static void read_ssnd_chunk( int fd, chunk_header_t *chunk_header,
  182.                     ssnd_chunk_t *ssnd_data ) ;
  183. static void reset_audio_hw( void ) ;
  184. static void set_gain( float l, float r ) ;
  185. static void set_rate(void);
  186. static void set_gain_index( unsigned long gain ) ;
  187. static void signal_sound( short *data, long size , long repeat) ;
  188. static void skip_chunk( int fd, chunk_header_t *chunk_header ) ;
  189. static void sound_handler( void *arg ) ;
  190. static void wake_up( int sig, int code, struct sigcontext *sc ) ;
  191.  
  192.  
  193. int init_sound( void ) {
  194.     int    i ;
  195.     char fullpath[512];
  196.     FILE *f;
  197.  
  198.     if( ( has_sound_hw = check_for_audio_hw() ) != 0 ) {
  199.     if( ( audio_port[0] = init_audio_port( 1 ) ) == NULL ) {
  200.         fprintf( stderr, "%s: no audio ports available\n", basename ) ;
  201.         return( 1 ) ;
  202.     }
  203.  
  204.     if( ( audio_port[1] = init_audio_port( 0 ) ) != NULL ) {
  205.         audio_port[2] = init_audio_port( 0 ) ;
  206.     }
  207.     audio_port[3] = NULL ;
  208.  
  209.     
  210.     strcpy(fullpath, datadir);
  211.     strcat(fullpath, sound_file[0]);
  212.     f = fopen(fullpath, "r");
  213.     if (f == NULL) {
  214.         fprintf(stderr, "%s: cannot locate audio data\n",
  215.         basename);
  216.         gexit();
  217.         exit(1);
  218.     } else {
  219.         fclose(f);
  220.     }
  221.  
  222.     for( i = 0 ; i < SFX_N_SOUNDS ; i++ ) {
  223.         sound_data[i] = (short *)load_aiff_file( datadir,
  224.             sound_file[i], &sound_size[i] ) ;
  225.         sound_repeat[i] = 0;
  226.     }
  227.  
  228.     if( sound_data[SFX_EXPLOSION_L] ) {
  229.         init_pan_data(SFX_EXPLOSION_L) ;
  230.     }
  231.     if (sound_data[SFX_LIFT_L] ) {
  232.         init_pan_data(SFX_LIFT_L) ;
  233.     }
  234.     if (sound_data[SFX_TUNE_A]) {
  235.         sound_repeat[SFX_TUNE_A] = sound_size[SFX_TUNE_A];
  236.     }
  237.     if (sound_data[SFX_TUNE_B]) {
  238.         sound_repeat[SFX_TUNE_B] = sound_size[SFX_TUNE_B];
  239.     }
  240.     if (sound_data[SFX_TUNE_C]) {
  241.         sound_repeat[SFX_TUNE_C] = sound_size[SFX_TUNE_C];
  242.     }
  243.     if( ( sound_child = sproc( sound_handler, PR_SALL, audio_port ) ) < 0 ){
  244.         fprintf( stderr, "%s: could not sproc sound handler: %s\n",
  245.                  basename, strerror( errno ) ) ;
  246.         return( 1 ) ;
  247.     } else {
  248.         sound_enabled = 1 ;
  249.     }
  250.     } else {
  251.     sound_enabled = 0 ;
  252.     return( 1 ) ;
  253.     }
  254.     
  255.  
  256.     return( 0 ) ;
  257. }
  258.  
  259.  
  260.  
  261. void set_volume(int level) {
  262.     if( level >= 0 &&
  263.         level < sizeof( gain_settings ) / sizeof( gain_settings[0] ) ) {
  264.     gain_index = level ;
  265.     curr_left_gain = curr_right_gain = gain_settings[gain_index] ;
  266.     }
  267. }
  268.  
  269.  
  270.  
  271. int toggle_sound( void ) {
  272.     if( has_sound_hw && sound_child )
  273.     sound_enabled = !sound_enabled ;
  274.  
  275.     return( sound_enabled ) ;
  276. }
  277.  
  278.  
  279. int toggle_tune( void ) {
  280.     if( has_sound_hw && sound_child )
  281.     tune_enabled = !tune_enabled ;
  282.  
  283.     return( tune_enabled ) ;
  284. }
  285.  
  286. void tune_off(void) {
  287.     tune_enabled = 0;
  288. }
  289.  
  290.  
  291. void end_sound( void ) {
  292.     if( sound_child > 0 ) {
  293.     kill( sound_child, SIGKILL ) ;
  294.     }
  295.     if( has_sound_hw )
  296.     reset_audio_hw() ;
  297. }
  298.  
  299.  
  300. /* ARGSUSED */
  301. static void wake_up(int sig, int code, struct sigcontext *sc) {
  302.     signal( SIGUSR1, wake_up ) ;
  303. }
  304.  
  305.  
  306.  
  307. static void reset_audio_hw( void ) {
  308.     long    pvbuf[6] ;
  309.     long    buflen ;
  310.  
  311.     pvbuf[0] = AL_LEFT_SPEAKER_GAIN ;
  312.     pvbuf[1] = orig_left_gain ;
  313.     pvbuf[2] = AL_RIGHT_SPEAKER_GAIN ;
  314.     pvbuf[3] = orig_right_gain ;
  315.     pvbuf[4] = AL_OUTPUT_RATE ;
  316.     pvbuf[5] = orig_output_rate ;
  317.     buflen = 6 ;
  318.  
  319.     ALsetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  320. }
  321.  
  322.  
  323.  
  324. static void set_gain(float l, float r) {
  325.     long    pvbuf[6] ;
  326.     long    buflen ;
  327.  
  328.     pvbuf[0] = AL_LEFT_SPEAKER_GAIN ;
  329.     pvbuf[1] = l * curr_left_gain ;
  330.     pvbuf[2] = AL_RIGHT_SPEAKER_GAIN ;
  331.     pvbuf[3] = r * curr_right_gain ;
  332.     pvbuf[4] = AL_OUTPUT_RATE ;
  333.     pvbuf[5] = AL_RATE_16000 ;
  334.     buflen = 6 ;
  335.     ALsetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  336. }
  337.  
  338. static void set_rate(void) {
  339.     long    pvbuf[2] ;
  340.     long    buflen ;
  341.  
  342.     pvbuf[0] = AL_OUTPUT_RATE ;
  343.     pvbuf[1] = AL_RATE_16000 ;
  344.     buflen = 2 ;
  345.     ALsetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  346. }
  347.  
  348.  
  349. static void sound_handler(void *arg) {
  350.     ALport    *ap = (ALport *)arg ;
  351.     int        i ;
  352.     int        empty ;
  353.     int        next_port = 0 ;
  354.     int        n_audio_ports ;
  355.     long    max_samps_per_frame ;
  356.     long    samps_to_play[MAX_AUDIO_PORTS] ;
  357.     long    samps_played[MAX_AUDIO_PORTS] ;
  358.     long    samps_repeat[MAX_AUDIO_PORTS] ;
  359.     short    *sample[MAX_AUDIO_PORTS] ;
  360.     
  361.     max_samps_per_frame = TIMECHUNK * 16000. ;
  362.     prctl(PR_TERMCHILD);
  363.     n_audio_ports = 0 ;
  364.     while( ap[n_audio_ports] != NULL ) {
  365.     sample[n_audio_ports] = 0 ;
  366.     samps_to_play[n_audio_ports] = 0 ;
  367.     samps_repeat[n_audio_ports] = 0;
  368.     n_audio_ports++ ;
  369.     }
  370.  
  371.     signal( SIGUSR1, wake_up ) ;
  372.  
  373.     while( 1 ) {
  374.     if( new_sound ) {
  375.         sample[next_port] = new_sound_data ;
  376.         samps_to_play[next_port] = new_sound_size ;
  377.         samps_repeat[next_port] = new_sound_repeat;
  378.         samps_played[next_port] = 0 ;
  379.         new_sound = 0 ;
  380.         next_port = ( next_port + 1 ) % n_audio_ports ;
  381.         if (samps_repeat[next_port] != 0) {
  382.         next_port = ( next_port + 1 ) % n_audio_ports ;
  383.         }
  384.     }
  385.     empty = 1 ;
  386.     for( i = 0 ; i < n_audio_ports ; i++ ) {
  387.         if( samps_to_play[i] > 0 ) {
  388.         if( samps_to_play[i] > max_samps_per_frame ) {
  389.             if (samps_repeat[i] != 0) {
  390.             if (!(tune_enabled && sound_enabled)) {
  391.                 /* switch off tune */
  392.                 samps_to_play[i] = 0;
  393.                 samps_repeat[i] = 0;
  394.                 continue;
  395.             }
  396.             }
  397.             set_rate();
  398.             ALwritesamps( ap[i], sample[i] + samps_played[i],
  399.                 max_samps_per_frame ) ;
  400.             samps_played[i] += max_samps_per_frame ;
  401.             samps_to_play[i] -= max_samps_per_frame ;
  402.             empty = 0 ;
  403.         } else {
  404.             set_rate();
  405.             ALwritesamps( ap[i], sample[i] + samps_played[i],
  406.                 samps_to_play[i] ) ;
  407.             if (samps_repeat[i] != 0 && tune_enabled && sound_enabled) {
  408.             samps_to_play[i] = samps_repeat[i];
  409.             samps_played[i] = 0;
  410.             empty = 0;
  411.             } else { 
  412.             samps_to_play[i] = 0 ;
  413.             samps_repeat[i] = 0;
  414.             }
  415.         }
  416.         }
  417.         }
  418.     if (empty)
  419.         pause();
  420.     }
  421. }
  422.  
  423.  
  424.  
  425. void sfx(int sound) {
  426.     if ((sound != SFX_TUNE_A && sound != SFX_TUNE_B &&
  427.          sound != SFX_TUNE_C) || tune_enabled == 1 ) {
  428.     if( audio_port[0] && sound_data[sound] && sound_enabled ) {
  429.         signal_sound( sound_data[sound], sound_size[sound],
  430.             sound_repeat[sound] ) ;
  431.     }
  432.     }
  433. }
  434.  
  435.  
  436. /*_________________________________________________________________________
  437.  |
  438.  | sfx_pan - produce noise at panned position
  439.  | 
  440.  | This uses a clever trick, to use the data, one word shifted as the
  441.  | left/right difference. This works, because for stereo, the left and
  442.  | right samples are stored alternatly.
  443.  | However, for the sound in the middle, you need a separate data stream
  444.  | That is the reason why the explosion and lift sound are loaded twice
  445.  | above (which was just my laziness of programming).
  446.  |
  447. */
  448.  
  449. void sfx_pan(int sound, int pan) {
  450.     int        offset;
  451.  
  452.     if( sound_data[sound] && sound_enabled ) {
  453.     switch (pan) {
  454.         case -1:
  455.         offset = 0;
  456.         sound++;
  457.         break;
  458.         case 1:
  459.         offset = 1;
  460.         sound++;
  461.         default:
  462.         offset = 0;
  463.         break;
  464.     }
  465.     signal_sound( sound_data[sound] + offset, sound_size[sound] - offset*2,0) ;
  466.     }
  467. }
  468.  
  469.  
  470. static void signal_sound(short *data, long size, long repeat ) {
  471.     if( sound_child ) {
  472.     new_sound_data = data ;
  473.     new_sound_size = size ;
  474.     new_sound_repeat = repeat;
  475.     new_sound = 1 ;
  476.     kill( sound_child, SIGUSR1 ) ;
  477.     }
  478. }
  479.  
  480. static void get_gain(void) {
  481.     long        pvbuf[6] ;
  482.     long        buflen ;
  483.     pvbuf[0] = AL_LEFT_SPEAKER_GAIN ;
  484.     pvbuf[2] = AL_RIGHT_SPEAKER_GAIN ;
  485.     buflen = 4 ;
  486.     ALgetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  487.     curr_left_gain = orig_left_gain = pvbuf[1] ;
  488.     curr_right_gain = orig_right_gain = pvbuf[3] ;
  489.  
  490.     set_gain_index( ( orig_left_gain + orig_right_gain ) / 2 ) ;
  491.     
  492. }
  493.  
  494. static ALport init_audio_port(int all) {
  495.     long        pvbuf[6] ;
  496.     long        buflen ;
  497.     ALconfig    audio_port_config;
  498.     ALport        ap ;
  499.  
  500.     if( all ) {
  501.     pvbuf[0] = AL_LEFT_SPEAKER_GAIN ;
  502.     pvbuf[2] = AL_RIGHT_SPEAKER_GAIN ;
  503.     pvbuf[4] = AL_OUTPUT_RATE ;
  504.     buflen = 6 ;
  505.     ALgetparams( AL_DEFAULT_DEVICE, pvbuf, buflen ) ;
  506.     curr_left_gain = orig_left_gain = pvbuf[1] ;
  507.     curr_right_gain = orig_right_gain = pvbuf[3] ;
  508.     orig_output_rate = pvbuf[5] ;
  509.  
  510.     set_gain_index( ( orig_left_gain + orig_right_gain ) / 2 ) ;
  511.     }
  512.  
  513.     /*
  514.      * configure and open audio port
  515.      */
  516.     audio_port_config = ALnewconfig();
  517.     ALsetwidth( audio_port_config, AL_SAMPLE_16 ) ;
  518.     ALsetchannels( audio_port_config, AL_STEREO ) ;
  519.  
  520.     /*
  521.      * make the ring buffer large enough to hold TIMECHUNK sec of audio samples
  522.      */
  523.     ALsetqueuesize( audio_port_config, 16000 * TIMECHUNK ) ;
  524.     ap = ALopenport( basename, "w", audio_port_config ) ;
  525.  
  526.     ALfreeconfig( audio_port_config ) ;
  527.  
  528.     return( ap ) ;
  529. }
  530.  
  531.  
  532.  
  533. static char *load_aiff_file(char *dir, char *name, long *size) {
  534.     int        fd ;
  535.     char    *data ;
  536.  
  537.     filename = (char *)malloc( strlen( name ) + strlen( dir ) + 3 ) ;
  538.     sprintf( filename, "%s/%s", dir, name ) ;
  539.  
  540.     if( ( fd = open( filename, O_RDONLY ) ) < 0 ) {
  541.     fprintf( stderr, "%s: can't open %s: %s\n", basename, filename,
  542.         strerror( errno ) ) ;
  543.     free( filename ) ;
  544.     return( NULL ) ;
  545.     }
  546.  
  547.     data = read_aiff_file( fd, size ) ;
  548.  
  549.     free( filename ) ;
  550.  
  551.     close( fd ) ;
  552.  
  553.     return( data ) ;
  554. }
  555.  
  556.  
  557.  
  558. static char *read_aiff_file(int fd, long *size ) {
  559.     int                n ;
  560.     chunk_header_t    chunk_header ;
  561.     comm_chunk_t    comm_data ;
  562.     ssnd_chunk_t    ssnd_data ;
  563.     audio_params_t    audio_params ;
  564.  
  565.     if( ( n = read_chunk_header( fd, &chunk_header ) ) != CHUNK_HEADER ) {
  566.         fprintf( stderr, "%s: failed to read FORM chunk header\n", basename ) ;
  567.         return( NULL ) ;
  568.         }
  569.  
  570.     if( strncmp( chunk_header.id, "FORM", 4 ) ) {
  571.         fprintf( stderr, "%s: couldn't find FORM chunk id\n", basename ) ;
  572.         return( NULL ) ;
  573.         }
  574.  
  575.     read_form_chunk( fd, &chunk_header ) ;
  576.  
  577.     /*
  578.      * loop on the local chunks
  579.      */
  580.     while( ( n = read_chunk_header( fd, &chunk_header ) ) != 0 ) {
  581.         if( n != CHUNK_HEADER ) {
  582.             fprintf( stderr, "%s: failed to read a chunk header\n", basename ) ;
  583.             return( NULL ) ;
  584.             }
  585.  
  586.         /* common */
  587.         if( !strncmp( chunk_header.id, "COMM", 4 ) ) {
  588.             read_comm_chunk( fd, &comm_data, &audio_params ) ;
  589.             }
  590.         /* sound data */
  591.         else if( !strncmp( chunk_header.id, "SSND", 4 ) ) {
  592.             read_ssnd_chunk( fd, &chunk_header, &ssnd_data ) ;
  593.             }
  594.         else if( ( !strncmp( chunk_header.id, "MARK", 4 ) )  /* marker */
  595.               || ( !strncmp( chunk_header.id, "INST", 4 ) )  /* instrument */
  596.               || ( !strncmp( chunk_header.id, "APPL", 4 ) )  /* appl specific */
  597.               || ( !strncmp( chunk_header.id, "MIDI", 4 ) )  /* midi data */
  598.               || ( !strncmp( chunk_header.id, "AESD", 4 ) )  /* audio  rec */
  599.               || ( !strncmp( chunk_header.id, "COMT", 4 ) )  /* comments */
  600.               || ( !strncmp( chunk_header.id, "NAME", 4 ) )  /* text */
  601.               || ( !strncmp( chunk_header.id, "AUTH", 4 ) )  /* text */
  602.               || ( !strncmp( chunk_header.id, "(c) ", 4 ) )  /* text */
  603.               || ( !strncmp( chunk_header.id, "ANNO", 4 ) )  /* text */
  604.             ) {
  605.             skip_chunk( fd, &chunk_header ) ;
  606.             }
  607.         else {
  608.             fprintf( stderr, "%s: bad chunk id  0x%02x%02x%02x%02x\n",
  609.                      basename, chunk_header.id[0],chunk_header.id[1],
  610.                      chunk_header.id[2], chunk_header.id[3]);
  611.             }
  612.         } /* while */
  613.  
  614.     return( init_audio( fd, &audio_params, &ssnd_data, &comm_data, size ) ) ;
  615. }
  616.  
  617.  
  618.  
  619. /*
  620.  * R E A D _ C H U N K _ H E A D E R
  621.  */
  622. static int read_chunk_header(int fd, chunk_header_t *chunk_header ) {
  623.     align_long_t    align_long ;
  624.     char            buf[CHUNK_HEADER] ;
  625.     int                i ;
  626.     int                n ;
  627.  
  628.     if( ( n = read( fd, buf, CHUNK_HEADER) ) != CHUNK_HEADER ) {
  629.         return( n ) ;
  630.         }
  631.  
  632.     for( i = 0 ; i < 4 ; i++ ) {
  633.         chunk_header->id[i] = buf[i] ;
  634.         }
  635.  
  636.     for( i = 0 ; i < 4 ; i++ ) {
  637.         align_long.b[i] = buf[i+4] ;
  638.         } 
  639.     chunk_header->size = align_long.l ;
  640.  
  641.     return( CHUNK_HEADER ) ;
  642. }
  643.  
  644.  
  645.  
  646.  
  647. static void read_form_chunk(int fd, chunk_header_t *chunk_header ) {
  648.     char buf[FORM_CHUNK_DATA];
  649.  
  650.     if( chunk_header->size < 0 ) {
  651.         fprintf( stderr, "%s: invalid FORM chunk data size %ld\n", basename,
  652.         chunk_header->size ) ;
  653.     gexit();
  654.         exit( 1 ) ;
  655.     } else if( chunk_header->size == 0 ) {
  656.         fprintf( stderr, "%s: FORM chunk data size = 0\n", basename ) ;
  657.         gexit();
  658.     exit( 0 ) ;
  659.     } 
  660.  
  661.     if( read( fd, buf, FORM_CHUNK_DATA ) != FORM_CHUNK_DATA ) {
  662.         fprintf( stderr, "%s: couldn't read AIFF identifier from %s\n",
  663.         basename, filename ) ;
  664.     gexit();
  665.         exit( 1 ) ;
  666.     }
  667.     if( strncmp( buf, "AIFF", 4 ) ) {
  668.     fprintf( stderr, "%s: %s does not have an AIFF identifier\n",
  669.         basename, filename ) ;
  670.     gexit();
  671.     exit(1);
  672.     }
  673. }
  674.  
  675.  
  676.  
  677. /*
  678.  * R E A D _ C O M M _ C H U N K
  679.  */
  680. static void read_comm_chunk(int fd, comm_chunk_t *comm_data,
  681.     audio_params_t *audio_params) {
  682.     int n;
  683.     char *buf, *bufp;
  684.     int i;
  685.     align_short_t align_short;
  686.     align_long_t  align_long;
  687.     double tmpdouble;
  688.  
  689.     buf = (char *) malloc(COMM_CHUNK_DATA + 1); /* leave an extra loc at the end */
  690.  
  691.     if ((n = read(fd,  buf, COMM_CHUNK_DATA)) != COMM_CHUNK_DATA)
  692.     {
  693.         fprintf(stderr, 
  694.         "%s: failed to read COMM chunk data. Expected %d bytes, got %d.\n",
  695.             basename, COMM_CHUNK_DATA, n); 
  696.     gexit();
  697.         exit(1);
  698.     }
  699.     bufp = buf;
  700.     for (i=0; i<2; i++)
  701.     {
  702.        align_short.b[i] = *bufp++;
  703.     }
  704.     comm_data->nchannels = align_short.s;
  705.     for (i=0; i<4; i++) 
  706.     { 
  707.        align_long.b[i]  = *bufp++;
  708.     }
  709.     comm_data->nsampframes = align_long.l;
  710.     for (i=0; i<2; i++)
  711.     {
  712.        align_short.b[i] = *bufp++;
  713.     }
  714.     comm_data->sampwidth = align_short.s; 
  715.  
  716.     /*
  717.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  718.      * floating point number:
  719.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  720.      *
  721.      */
  722.     tmpdouble = ConvertFromIeeeExtended(bufp);
  723.     bufp+=10;
  724.     comm_data->samprate = (long)tmpdouble;
  725.  
  726.     switch (comm_data->samprate)
  727.     {
  728.         case 48000:
  729.         audio_params->samprate = AL_RATE_48000;        
  730.         break;
  731.     case 44100:
  732.         audio_params->samprate = AL_RATE_44100;
  733.         break;
  734.     case 32000:
  735.         audio_params->samprate = AL_RATE_32000;
  736.         break;
  737.     case 22050:
  738.         audio_params->samprate = AL_RATE_22050;
  739.         break;
  740.     case 16000:
  741.         audio_params->samprate = AL_RATE_16000;
  742.         break;
  743.     case 11025:
  744.         audio_params->samprate = AL_RATE_11025;
  745.         break;
  746.     case  8000:
  747.         audio_params->samprate = AL_RATE_8000;
  748.         break;
  749.         default:
  750.                 fprintf(stderr,"%s: can't set output sample rate to %ld\n",
  751.                             basename, comm_data->samprate);
  752.         audio_params->samprate = AL_RATE_48000;        
  753.     }
  754.  
  755.     switch (comm_data->nchannels)
  756.     {
  757.     case 1:
  758.         audio_params->nchannels = AL_MONO;
  759.         break;
  760.     case 2:
  761.         audio_params->nchannels = AL_STEREO;
  762.         break;
  763.     default:
  764.         fprintf(stderr, "%s: can't handle %d channels per frame\n",
  765.                     basename, comm_data->nchannels);
  766.         audio_params->nchannels = AL_STEREO;
  767.     }
  768.     switch (comm_data->sampwidth)
  769.     {
  770.     case 8:
  771.          audio_params->sampwidth = AL_SAMPLE_8;
  772.         break;
  773.     case 16:
  774.          audio_params->sampwidth = AL_SAMPLE_16;
  775.         break;
  776.     case 24:
  777.          audio_params->sampwidth = AL_SAMPLE_24;
  778.         break;
  779.     default:
  780.         fprintf(stderr, "%s: unsupported sample width %d bits\n",
  781.             basename, comm_data->nchannels);
  782.          audio_params->sampwidth = AL_SAMPLE_16;
  783.     }
  784.     free(buf);
  785. }
  786.  
  787.  
  788.  
  789. static void read_ssnd_chunk(
  790.     int fd,
  791.     chunk_header_t *chunk_header,
  792.     ssnd_chunk_t *ssnd_data
  793.     )
  794. {
  795.     char buf[SSND_CHUNK_DATA];
  796.     int i;
  797.     align_long_t align_long;
  798.  
  799.     read(fd, buf, SSND_CHUNK_DATA);
  800.  
  801.     for (i=0; i<4; i++)
  802.     {
  803.         align_long.b[i] = buf[i];
  804.     }
  805.     ssnd_data->offset = align_long.l;
  806.     for (i=0; i<4; i++)
  807.     {
  808.         align_long.b[i] = buf[i+4];
  809.     }
  810.     ssnd_data->blocksize = align_long.l;
  811.     /*
  812.      * store the offset to the beginning of the audio sample data so that
  813.      * we can come back and play it later
  814.      */ 
  815.     ssnd_data->file_position = lseek(fd, 0, SEEK_CUR);
  816.     ssnd_data->sample_area_bytes = chunk_header->size - 2*sizeof(long);
  817.     if (chunk_header->size %2 == 1)
  818.     {
  819.         ssnd_data->sample_area_bytes++;
  820.     }
  821.  
  822.     /*
  823.      * move the fileptr to the end of the chunk
  824.      */
  825.     lseek(fd, ssnd_data->sample_area_bytes, SEEK_CUR);
  826. }
  827.  
  828.  
  829.  
  830. /*
  831.  * S K I P _ C H U N K
  832.  */
  833. static void skip_chunk(
  834.     int fd,
  835.     chunk_header_t *chunk_header
  836.     )
  837. {
  838.     char id[5];
  839.     int s;
  840.  
  841.     strncpy(id, chunk_header->id, 4);
  842.     id[4] = '\0'; 
  843.  
  844.     /* skip the pad byte, if necessary */
  845.     s = ((chunk_header->size % 2) == 1) ? chunk_header->size + 1 : chunk_header->size;
  846.     lseek(fd, s, SEEK_CUR);
  847. }
  848.  
  849.  
  850.  
  851.  
  852. /*
  853.  * C O N V E R T   F R O M   I E E E   E X T E N D E D  
  854.  */
  855.  
  856. /* 
  857.  * Copyright (C) 1988-1991 Apple Computer, Inc.
  858.  * All rights reserved.
  859.  *
  860.  * Warranty Information
  861.  *  Even though Apple has reviewed this software, Apple makes no warranty
  862.  *  or representation, either express or implied, with respect to this
  863.  *  software, its quality, accuracy, merchantability, or fitness for a
  864.  *  particular purpose.  As a result, this software is provided "as is,"
  865.  *  and you, its user, are assuming the entire risk as to its quality
  866.  *  and accuracy.
  867.  *
  868.  * This code may be used and freely distributed as long as it includes
  869.  * this copyright notice and the above warranty information.
  870.  
  871.  * Machine-independent I/O routines for IEEE floating-point numbers.
  872.  *
  873.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  874.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  875.  * impossible to preserve NaN's in a machine-independent way.
  876.  * Infinities are, however, preserved on IEEE machines.
  877.  *
  878.  * These routines have been tested on the following machines:
  879.  *    Apple Macintosh, MPW 3.1 C compiler
  880.  *    Apple Macintosh, THINK C compiler
  881.  *    Silicon Graphics IRIS, MIPS compiler
  882.  *    Cray X/MP and Y/MP
  883.  *    Digital Equipment VAX
  884.  *
  885.  *
  886.  * Implemented by Malcolm Slaney and Ken Turkowski.
  887.  *
  888.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  889.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  890.  * floating-point format, and conversions to and from IEEE single-
  891.  * precision floating-point format.
  892.  *
  893.  * In 1991, Ken Turkowski implemented the conversions to and from
  894.  * IEEE double-precision format, added more precision to the extended
  895.  * conversions, and accommodated conversions involving +/- infinity,
  896.  * NaN's, and denormalized numbers.
  897.  */
  898.  
  899. #ifndef HUGE_VAL
  900. # define HUGE_VAL HUGE
  901. #endif /* HUGE_VAL */
  902.  
  903. # define UnsignedToFloat(u)    \
  904.      (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
  905.  
  906. /****************************************************************
  907.  * Extended precision IEEE floating-point conversion routine.
  908.  ****************************************************************/
  909.  
  910. static double ConvertFromIeeeExtended(char *bytes) {
  911.     double            f ;
  912.     long            expon ;
  913.     unsigned long    hiMant ;
  914.     unsigned long    loMant ;
  915.  
  916.     expon = ( ( bytes[0] & 0x7F ) << 8 ) | ( bytes[1] & 0xFF ) ;
  917.     hiMant = ( (unsigned long)( bytes[2] & 0xFF ) << 24 )
  918.        | ( (unsigned long)( bytes[3] & 0xFF ) << 16 )
  919.        | ( (unsigned long)( bytes[4] & 0xFF ) << 8  )
  920.        | ( (unsigned long)( bytes[5] & 0xFF ) ) ;
  921.     loMant = ( (unsigned long)( bytes[6] & 0xFF ) << 24 )
  922.        | ( (unsigned long)( bytes[7] & 0xFF ) << 16 )
  923.        | ( (unsigned long)( bytes[8] & 0xFF ) << 8  )
  924.        | ( (unsigned long)( bytes[9] & 0xFF ) ) ;
  925.  
  926.     if( expon == 0 && hiMant == 0 && loMant == 0 ) {
  927.     f = 0;
  928.     } else {
  929.     if( expon == 0x7FFF ) {    /* Infinity or NaN */
  930.         f = HUGE_VAL;
  931.         } else {
  932.         expon -= 16383;
  933.         f  = ldexp( UnsignedToFloat( hiMant ), expon-=31 ) ;
  934.         f += ldexp( UnsignedToFloat( loMant ), expon-=32 ) ;
  935.     }
  936.     }
  937.  
  938.     if( bytes[0] & 0x80 )
  939.         return( -f ) ;
  940.     else
  941.         return( f ) ;
  942. }
  943.  
  944.  
  945.  
  946. /*
  947.  * I N I T _ A U D I O
  948.  */
  949. static char *init_audio( int fd, audio_params_t *audio_params, 
  950.     ssnd_chunk_t *ssnd_data, comm_chunk_t *comm_data,
  951.     long *size) {
  952.     
  953.     char    *buf ;
  954.     int        bytes_read ;
  955.  
  956.     /*
  957.      * decide what size blocks of samples we should read from the
  958.      * AIFF file and pass to ALwritesamps
  959.      */
  960.     switch( audio_params->sampwidth ) {
  961.         default :
  962.         case AL_SAMPLE_8 :
  963.         fprintf( stderr, "%s: sound file %s is not 16 bytes/sample\n",
  964.             basename, filename ) ;
  965.         return( NULL ) ;
  966.  
  967.         case AL_SAMPLE_16 :
  968.         bytes_per_samp = 2 ;
  969.         break ;
  970.     }
  971.  
  972.     switch( audio_params->nchannels ) {
  973.         default :
  974.         case AL_MONO :
  975.         fprintf( stderr, "%s: sound file %s is not in stereo\n",
  976.             basename, filename ) ;
  977.         return( NULL ) ;
  978.       
  979.         case AL_STEREO :
  980.         samps_per_frame = 2 ;
  981.         break ;
  982.     }
  983.  
  984.     switch( audio_params->samprate ) {
  985.         default :
  986.         case AL_RATE_48000 :
  987.         case AL_RATE_44100 :
  988.         case AL_RATE_32000 :
  989.         case AL_RATE_22050 :
  990.         case AL_RATE_11025 :
  991.         case AL_RATE_8000 :
  992.         fprintf( stderr,
  993.             "%s: sound file %s is not sampled at 16KHz\n",
  994.             basename, filename ) ;
  995.         return(  NULL ) ;
  996.         case AL_RATE_16000 :
  997.         frames_per_sec = 16000 ;
  998.         break ;
  999.     }
  1000.  
  1001.     *size = comm_data->nsampframes * samps_per_frame * bytes_per_samp ;
  1002.  
  1003.     buf = (char *)malloc( *size ) ;
  1004.     lseek( fd, ssnd_data->file_position, SEEK_SET ) ;
  1005.     if( ( bytes_read = read( fd, buf, *size ) ) < *size ) {
  1006.     fprintf( stderr, "%s: short read on %s\n", basename, filename ) ;
  1007.     *size = bytes_read ;
  1008.     }
  1009.  
  1010.     *size /= samps_per_frame ;
  1011.  
  1012.     return( buf ) ;
  1013. }
  1014.  
  1015.  
  1016. #ifndef INV_AUDIO_A2
  1017. #define INV_AUDIO_A2 3        /* HAL2 Audio Module for Indigo 2 */
  1018. #endif
  1019.  
  1020. static int check_for_audio_hw( void ) {
  1021.     int        st = 0;
  1022.     inventory_t    *base;
  1023.     inventory_t    *inv;
  1024.  
  1025.  
  1026.     inv = base = getinvent() ;
  1027.     while (inv != NULL) {
  1028.  
  1029. #ifdef OLD_STYLE_INVENT
  1030.     if (inv->class == INV_AUDIO && (inv->type == INV_AUDIO_HDSP 
  1031.         || inv->type == INV_AUDIO_A2)) {
  1032.         st = 1;
  1033.     }
  1034. #else
  1035.     if (inv->inv_class == INV_AUDIO && (inv->inv_type == INV_AUDIO_HDSP 
  1036.         || inv->inv_type == INV_AUDIO_A2)) {
  1037.         st = 1;
  1038.     }
  1039. #endif
  1040.     inv = getinvent() ;
  1041.     }
  1042.  
  1043.     if (base) {
  1044.     endinvent();
  1045.     }
  1046.  
  1047.     return( st ) ;
  1048. }
  1049.  
  1050.  
  1051.  
  1052. int volume_change(int direction) {
  1053.     
  1054.     get_gain();
  1055.     if( direction == 1 ) {
  1056.     if( gain_index <
  1057.         sizeof( gain_settings ) / sizeof( gain_settings[0] ) - 1 ) {
  1058.         gain_index++ ;
  1059.     }
  1060.     } else {
  1061.     if( gain_index > 0 ) {
  1062.         gain_index-- ;
  1063.     }
  1064.     }
  1065.     curr_left_gain = curr_right_gain = gain_settings[gain_index] ;
  1066.  
  1067.     set_gain( 1., 1. ) ;
  1068.  
  1069.     return( gain_index ) ;
  1070. }
  1071.  
  1072.  
  1073.  
  1074. static void set_gain_index(unsigned long gain) {
  1075.     int        i ;
  1076.     long    min = 256 ;
  1077.     long    diff ;
  1078.  
  1079.     for (i = 0; i < sizeof(gain_settings) / sizeof(gain_settings[0]); i++ ) {
  1080.     diff = gain - gain_settings[i] ;
  1081.     if( diff < 0 )
  1082.         diff = -diff ;
  1083.     if( diff < min ) {
  1084.         min = diff ;
  1085.         gain_index = i ;
  1086.     }
  1087.     }
  1088. }
  1089.  
  1090.  
  1091.  
  1092. static void init_pan_data( int sound ) {
  1093.     int    i;
  1094.     int size;
  1095.     short *s;
  1096.     
  1097.     size = sound_size[sound]-1;
  1098.     s = sound_data[sound]+1;
  1099.     for( i = 0 ; i < size; i += 2 ) {
  1100.     *(s+i) /= 2;
  1101.     }
  1102. }
  1103.